package com.lxb.myforum.service

import java.util.HashMap

import javax.transaction.Transactional

import com.lxb.myforum.base.BaseService
import org.apache.commons.lang3.StringUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service

import com.lxb.myforum.pojo.Role
import com.lxb.myforum.pojo.User
import com.lxb.myforum.repository.RoleRepository
import com.lxb.myforum.repository.UserRepository
import com.lxb.myforum.service.spec.UserSpec

/**
 *
 * @author lxb
 */
@Service
class UserService @Autowired constructor(
        private val userRepository: UserRepository,
        private val roleRepository: RoleRepository,
        private val namedParameterJdbcTemplate: NamedParameterJdbcTemplate
) : BaseService() {

    @Bean
    fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }

    /**
     * 保存用户 （新增或者更新）
     * @param u [User]
     * @return
     */
    fun saveUser(u: User): User {
        if (StringUtils.isNotEmpty(u.password)) {
            u.password = passwordEncoder().encode(u.password)
        }
        return userRepository.save(u)
    }

    /**
     * 根据条件查询数据个数
     * @param user
     * @return
     */
    fun count(user: User): Long {
        return userRepository.count(UserSpec(user))
    }

    /**
     * 查询所有数据个数
     * @return 用户的数量
     */
    fun count(): Long {
        return userRepository.count()
    }


    fun loadUserByUsername(username: String): UserDetails? {
        userRepository.findUserByUsername(username)
        return null
    }

    fun getUsers(pageable: Pageable): Page<User> {
        return userRepository.findAll(pageable)
    }

    fun findOwnRoles(userId: Long): List<Role> {
        return roleRepository.findOwnRoles(userId)
    }

    fun findNotOwnRoles(userId: Long): List<Role> {
        //		User u = userRepository.findOne(userId);
        //		List<Role> ownRoles =  u.getRoles();
        //		List<Role> roles = roleRepository.findAll(new Specification<Role>() {
        //			@Override
        //			public Predicate toPredicate(Root<Role> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        //				List<Predicate> predicates = ownRoles.stream().map(role -> {
        //					return cb.notEqual(root.get("id"), role.getId());
        //				}).collect(Collectors.toList());
        //				query.where(predicates.toArray(new Predicate[predicates.size()]));
        //				return null;
        //			}
        //		});
        return roleRepository.findNotUserRoles(userId)
    }

    /**
     * 删除用户角色
     * @param userId 用户id
     * @param roleIds 要添加的用户的角色id
     * @return
     */
    @Transactional
    fun delUserRoles(userId: Long, roleIds: Set<Long>): MutableMap<String, Any> {
        val result = HashMap<String, Any>()
        val delSql = "delete from t_user_role where user_id = :userId and role_id = :roleId"
        try {
            val batchValues = makeMapSqlParameterSource(userId, roleIds)
            namedParameterJdbcTemplate.batchUpdate(delSql, batchValues)

            result["result"] = 1
            result["msg"] = "删除成功"
        } catch (e: Exception) {
            result["result"] = -1
            result["msg"] = "删除失败"
        }

        return result
    }

    /**
     * 为用户添加角色
     * @param userId 用户id
     * @param roleIds 要添加的用户的角色id
     * @return
     */
    @Transactional
    fun addUserRoles(userId: Long, roleIds: Set<Long>): MutableMap<String, Any> {
        val result = HashMap<String, Any>()
        try {
            val batchValues = makeMapSqlParameterSource(userId, roleIds)

            namedParameterJdbcTemplate.batchUpdate("insert into t_user_role(role_id, user_id) values(:roleId, :userId)", batchValues)

            result["result"] = 1
            result["msg"] = "添加成功"
        } catch (e: Exception) {
            result["result"] = -1
            result["msg"] = "添加失败"
        }

        return result
    }

    /**
     * 提取公共代码
     * @param userId 用户id
     * @param roleIds 所需角色id集合
     * @return [MapSqlParameterSource]
     */
    private fun makeMapSqlParameterSource(userId: Long, roleIds: Set<Long>): Array<MapSqlParameterSource> {

        return roleIds.stream()
                .map { roleId ->
                    val mapSqlParameterSource = MapSqlParameterSource("roleId", roleId)
                    mapSqlParameterSource.addValue("userId", userId)
                    mapSqlParameterSource
                }

                .toArray {
                    arrayOfNulls<MapSqlParameterSource>(it)
                }
    }

}
